﻿#include "SemiInfiniteFluidDialog.h"
#include "ui_SemiInfiniteFluidDialog.h"

#include "OperatorsInterface/ParaWidgetInterfaceOperator.h"
#include "OperatorsInterface/GraphEventOperator.h"

#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Kernel/FITKCore/FITKVec3D.h"
#include "FITK_Kernel/FITKCore/FITKOperatorRepo.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsSEAModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractSEASubSys.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEASubSysSemiInfiniteFluid.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscNodeList.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsPhysics.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsAbsMaterial.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsAbstractSpectra.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsSpectraManager.h"

#include <QMessageBox>

#define SemiInfiniteFluid_ConSubSysPos Qt::UserRole

namespace GUI
{
    SemiInfiniteFluidDialog::SemiInfiniteFluidDialog(int dataID, EventOper::ParaWidgetInterfaceOperator * oper, bool isCreate):
        GUIDialogBase(FITKAPP->getGlobalData()->getMainWindow()),
        _isCreate(isCreate), _oper(oper)
    {
        _ui = new Ui::SemiInfiniteFluidDialog();
        _ui->setupUi(this);

        if (isCreate == false) {
            _currentDataID = dataID;
        }

        init();
    }

    SemiInfiniteFluidDialog::~SemiInfiniteFluidDialog()
    {
        if (_ui) {
            delete _ui;
            _ui = nullptr;
        }
    }

    void SemiInfiniteFluidDialog::init()
    {
        if (_physics == nullptr && _physics->getMaterialManager() == nullptr)return;
        for (Acoustics::FITKAcousticsAbsMaterial* mat : _physics->getMaterialManager()->getAcousticsMaterials(Acoustics::FITKAcousticsAbsMaterial::AcousticsMaterialType::Fluid)) {
            if(mat == nullptr)continue;
            _ui->comboBox_Fluid->addItem(mat->getDataObjectName(), mat->getDataObjectID());
        }
        if (_ui->comboBox_Fluid->count() > 0)_ui->comboBox_Fluid->setCurrentIndex(0);

        QStringList nodeHeader;
        nodeHeader << QString(tr("ID")) << QString(tr("X")) << QString(tr("Y")) << QString(tr("Z"));
        _ui->tableWidget_Node->setColumnCount(4);
        _ui->tableWidget_Node->setRowCount(1);
        _ui->tableWidget_Node->setHorizontalHeaderLabels(nodeHeader);
        //自适应
        _ui->tableWidget_Node->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);

        _ui->checkBox_EnabledJunction->setChecked(true);

        QStringList connectHeader;
        connectHeader << QString(tr("Sybsystem")) << QString(tr("Face")) << QString(tr("Baffle Bound.Cond.")) 
            << QString(tr("Wetted Side")) << QString(tr("Area")) << QString(tr("Distance")) << QString(tr("Radiation Loss Factor"));
        _ui->tableWidget_ConSub->setColumnCount(7);
        _ui->tableWidget_ConSub->hideColumn(1);
        _ui->tableWidget_ConSub->hideColumn(2);
        _ui->tableWidget_ConSub->hideColumn(3);
        _ui->tableWidget_ConSub->hideColumn(4);
        _ui->tableWidget_ConSub->setHorizontalHeaderLabels(connectHeader);
        //自适应
        _ui->tableWidget_ConSub->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);

        _ui->checkBox_Override->setEnabled(false);
        _ui->pushButton_Remove->setEnabled(false);

        _ui->label_GeneralImage->setPixmap(QPixmap(":/icons/SemiInfiniteFluid.png"));

        if (_isCreate) {
            InitCreate();
            setWindowTitle(QString("Semi Infinite Fluid Create"));
        }
        else {
            InitEdit();
            setWindowTitle(QString("Semi Infinite Fluid Edit"));
            _ui->lineEdit_Name->setEnabled(false);
        }
    }

    void SemiInfiniteFluidDialog::setNodeID(int nodeID)
    {
        updateNodeTable(nodeID);
    }

    void SemiInfiniteFluidDialog::showEvent(QShowEvent * event)
    {
        if (_isCreate == false) {
            GUIDialogBase::hightGraphObj(_currentDataID);
        }
        GUIDialogBase::showEvent(event);
    }

    void SemiInfiniteFluidDialog::disHight()
    {
        if (_isCreate == false && _currentDataID != -1) {
            disHightGraphObj(_currentDataID);
        }
    }

    void SemiInfiniteFluidDialog::accept()
    {
        disHight();
        GUIDialogBase::accept();
    }

    void SemiInfiniteFluidDialog::reject()
    {
        disHight();
        GUIDialogBase::reject();
    }

    void SemiInfiniteFluidDialog::on_pushButton_Ok_clicked()
    {
        if (_isCreate) {
            if (OKCreate() == false)return;
        }
        else {
            if (OKEdit() == false)return;
        }
        if (_oper) {
            _oper->setArgs(objID_String, _currentDataID);
            _oper->execProfession();
        }
        this->accept();
    }

    void SemiInfiniteFluidDialog::on_pushButton_Cancel_clicked()
    {
        this->reject();
    }

    void SemiInfiniteFluidDialog::on_pushButton_Remove_clicked()
    {
        int currentRow = _ui->tableWidget_ConSub->currentRow();
        _ui->tableWidget_ConSub->removeRow(currentRow);
    }

    void SemiInfiniteFluidDialog::on_checkBox_Override_clicked()
    {
        bool isChecked = _ui->checkBox_Override->isChecked();
        
        for (int i = 0; i < _ui->tableWidget_ConSub->rowCount(); i++) {
            QTableWidgetItem* item = _ui->tableWidget_ConSub->item(i, 5);
            if (item == nullptr)continue;
            if (isChecked)
                item->setFlags(item->flags() | Qt::ItemFlag::ItemIsEditable);
            else
                item->setFlags(Qt::ItemFlag::ItemIsEnabled);
        }
    }

    void SemiInfiniteFluidDialog::InitCreate()
    {
        if (_SEAModel == nullptr && _SEAModel->getSEASubSysManager() == nullptr)return;
        QString name = "Semi Infinite Fluid-0";
        name = _SEAModel->getSEASubSysManager()->checkName(name);
        _ui->lineEdit_Name->setText(name);
    }

    void SemiInfiniteFluidDialog::InitEdit()
    {
        if (_SEAModel == nullptr && _SEAModel->getSEASubSysManager() == nullptr)return;
        Acoustics::FITKSEASubSysSemiInfiniteFluid* sysData = dynamic_cast<Acoustics::FITKSEASubSysSemiInfiniteFluid*>(_SEAModel->getSEASubSysManager()->getDataByID(_currentDataID));
        if (sysData == nullptr)return;
        QString name = sysData->getDataObjectName();
        _ui->lineEdit_Name->setText(name);

        setDataToWidget(sysData);
    }

    bool SemiInfiniteFluidDialog::OKCreate()
    {
        if (_SEAModel == nullptr && _SEAModel->getSEASubSysManager() == nullptr)return false;
        QString name = _ui->lineEdit_Name->text();
        if (_SEAModel->getSEASubSysManager()->getDataByName(name)) {
            QMessageBox box(QMessageBox::Warning, "", QString(tr("\"%1\" Name exists!")).arg(name), QMessageBox::Ok);
            box.exec();
            return false;
        }

        Acoustics::FITKSEASubSysSemiInfiniteFluid* sysData = new Acoustics::FITKSEASubSysSemiInfiniteFluid();
        sysData->setDataObjectName(name);
        _currentDataID = sysData->getDataObjectID();
        getDataFromWidget(sysData);
        _SEAModel->getSEASubSysManager()->appendDataObj(sysData);
        return true;
    }

    bool SemiInfiniteFluidDialog::OKEdit()
    {
        if (_SEAModel == nullptr && _SEAModel->getSEASubSysManager() == nullptr)return false;

        auto subData = dynamic_cast<Acoustics::FITKSEASubSysSemiInfiniteFluid*>(_SEAModel->getSEASubSysManager()->getDataByID(_currentDataID));
        if (subData == nullptr)return false;

        getDataFromWidget(subData);
        return true;
    }

    void SemiInfiniteFluidDialog::getDataFromWidget(Acoustics::FITKSEASubSysSemiInfiniteFluid * data)
    {
        if (data == nullptr)return;
        data->setMaterialID(_ui->comboBox_Fluid->currentData().toInt());

        //存储node
        QTableWidgetItem* item = _ui->tableWidget_Node->item(0, 0);
        if (item) {
            data->setNodeID(item->text().toInt());
        }

        data->setIsEnabled(_ui->checkBox_EnabledJunction->isChecked());

        //存储connect
        QList<int> oldAllConIDs = {};
        for (int i = 0; i < data->getDataCount(); i++) {
            Acoustics::FITKSEASubSysSEIFConnectedSubSys* conSubSys = data->getDataByIndex(i);
            if (conSubSys == nullptr)continue;
            oldAllConIDs.append(conSubSys->getDataObjectID());
        }
        for (int i = 0; i < _ui->tableWidget_ConSub->rowCount(); i++) {
            QTableWidgetItem* item = _ui->tableWidget_ConSub->item(i, 0);
            if (item == nullptr)continue;
            int id = item->data(SemiInfiniteFluid_ConSubSysPos).toInt();
            Acoustics::FITKSEASubSysSEIFConnectedSubSys* conSubSys = data->getDataByID(id);
            if (conSubSys == nullptr)continue;
            
            item = _ui->tableWidget_ConSub->item(i, 5);
            if (item) {
                double distance = item->text().toDouble();
                conSubSys->setDistance(distance);
            }

            QComboBox* box = dynamic_cast<QComboBox*>(_ui->tableWidget_ConSub->cellWidget(i, 6));
            if (box != nullptr) {
                int radLossFacID = box->currentData().toInt();
                conSubSys->setRadLossFactorID(radLossFacID);
            }
            oldAllConIDs.removeAll(id);
        }
        for (int id : oldAllConIDs)data->removeDataByID(id);

        data->setIsOveSPLDistances(_ui->checkBox_Override->isChecked());
    }

    void SemiInfiniteFluidDialog::setDataToWidget(Acoustics::FITKSEASubSysSemiInfiniteFluid * data)
    {
        if (data == nullptr)return;
        _ui->comboBox_Fluid->setCurrentIndex(_ui->comboBox_Fluid->findData(data->getMaterialID()));

        updateNodeTable(data->getNodeID());
        _ui->checkBox_EnabledJunction->setChecked(data->getIsEnabled());
        updateConnectSubsys(data);
        _ui->checkBox_Override->setChecked(data->getIsOveSPLDistances());
    }

    void SemiInfiniteFluidDialog::updateNodeTable(int nodeID)
    {
        if (_DiscModel == nullptr && _DiscModel->getNodes() == nullptr) false;
        Core::FITKNode* node = _DiscModel->getNodes()->getNodeByID(nodeID);
        if (node == nullptr)return;
        QTableWidgetItem* item = new QTableWidgetItem();
        item->setText(QString::number(nodeID));
        item->setFlags(Qt::ItemIsEnabled);
        _ui->tableWidget_Node->setItem(0, 0, item);

        item = new QTableWidgetItem();
        item->setText(QString::number(node->x()));
        item->setFlags(Qt::ItemIsEnabled);
        _ui->tableWidget_Node->setItem(0, 1, item);

        item = new QTableWidgetItem();
        item->setText(QString::number(node->y()));
        item->setFlags(Qt::ItemIsEnabled);
        _ui->tableWidget_Node->setItem(0, 2, item);

        item = new QTableWidgetItem();
        item->setText(QString::number(node->z()));
        item->setFlags(Qt::ItemIsEnabled);
        _ui->tableWidget_Node->setItem(0, 3, item);
    }

    void SemiInfiniteFluidDialog::updateConnectSubsys(Acoustics::FITKSEASubSysSemiInfiniteFluid * data)
    {
        if (_SEAModel == nullptr && _SEAModel->getSEASubSysManager() == nullptr)return;
        if (data == nullptr)return;
        _ui->tableWidget_ConSub->setRowCount(0);
        for (int i = 0; i < data->getDataCount(); i++) {
            Acoustics::FITKSEASubSysSEIFConnectedSubSys* semSubSysCon = data->getDataByIndex(i);
            if (semSubSysCon == nullptr)continue;
            Acoustics::FITKAbstractSEASubSys* conSubSys = semSubSysCon->getSubSysObj();
            if (conSubSys == nullptr)continue;

            _ui->tableWidget_ConSub->setRowCount(i + 1);

            //名称添加
            QTableWidgetItem* item = new QTableWidgetItem();
            item->setText(conSubSys->getDataObjectName());
            item->setData(SemiInfiniteFluid_ConSubSysPos, semSubSysCon->getDataObjectID());
            item->setFlags(Qt::ItemFlag::ItemIsEnabled);
            _ui->tableWidget_ConSub->setItem(i, 0, item);

            switch (conSubSys->getSEASubSysType()){
            case Acoustics::FITKAbstractSEASubSys::SEABeam: {
                item = new QTableWidgetItem();
                item->setText("");
                item->setFlags(Qt::ItemFlag::ItemIsEnabled);
                _ui->tableWidget_ConSub->setItem(i, 1, item);
                item = new QTableWidgetItem();
                item->setText("");
                item->setFlags(Qt::ItemFlag::ItemIsEnabled);
                _ui->tableWidget_ConSub->setItem(i, 2, item);
                item = new QTableWidgetItem();
                item->setText("");
                item->setFlags(Qt::ItemFlag::ItemIsEnabled);
                _ui->tableWidget_ConSub->setItem(i, 3, item);
                break;
            }
            case Acoustics::FITKAbstractSEASubSys::SEAFlatPlate:
            case Acoustics::FITKAbstractSEASubSys::SEASinglyCurvedShell:
            case Acoustics::FITKAbstractSEASubSys::SEADoublyCurvedShell:
            case Acoustics::FITKAbstractSEASubSys::SEACylinderShell: {
                item = new QTableWidgetItem();
                item->setText("");
                item->setFlags(Qt::ItemFlag::ItemIsEnabled);
                _ui->tableWidget_ConSub->setItem(i, 1, item);
                item = new QTableWidgetItem();
                item->setText("Baffled");
                item->setFlags(Qt::ItemFlag::ItemIsEnabled);
                _ui->tableWidget_ConSub->setItem(i, 2, item);
                item = new QTableWidgetItem();
                item->setText("Front");
                item->setFlags(Qt::ItemFlag::ItemIsEnabled);
                _ui->tableWidget_ConSub->setItem(i, 3, item);
            }
                break;
            case Acoustics::FITKAbstractSEASubSys::SEACavity: {
                item = new QTableWidgetItem();
                item->setText(QString::number(semSubSysCon->getCavityFaceID()));
                item->setFlags(Qt::ItemFlag::ItemIsEnabled);
                _ui->tableWidget_ConSub->setItem(i, 1, item);
                item = new QTableWidgetItem();
                item->setText("Baffled");
                item->setFlags(Qt::ItemFlag::ItemIsEnabled);
                _ui->tableWidget_ConSub->setItem(i, 2, item);
                item = new QTableWidgetItem();
                item->setText("");
                item->setFlags(Qt::ItemFlag::ItemIsEnabled);
                _ui->tableWidget_ConSub->setItem(i, 3, item);
                break;
            }
            }

            //面积
            item = new QTableWidgetItem();
            item->setText(QString::number(0));
            item->setFlags(Qt::ItemFlag::ItemIsEnabled);
            _ui->tableWidget_ConSub->setItem(i, 4, item);

            //距离
            item = new QTableWidgetItem();
            item->setText(QString::number(semSubSysCon->getDistance()));
            if (data->getIsOveSPLDistances()) {
                item->setFlags(item->flags() | Qt::ItemFlag::ItemIsEditable);
            }
            else {
                item->setFlags(Qt::ItemFlag::ItemIsEnabled);
            }
            _ui->tableWidget_ConSub->setItem(i, 5, item);
            //损耗因子谱
            QComboBox* box = createRadLossFactor();
            box->setCurrentIndex(box->findData(semSubSysCon->getRadLossFactor()));
            _ui->tableWidget_ConSub->setCellWidget(i, 6, box);
        }

        if (_ui->tableWidget_ConSub->rowCount() > 0) {
            _ui->checkBox_Override->setEnabled(true);
            _ui->pushButton_Remove->setEnabled(true);
        }
    }

    QComboBox* SemiInfiniteFluidDialog::createRadLossFactor()
    {
        QComboBox* box = new QComboBox(this);
        box->addItem("Analytical", -1);

        if (_physics == nullptr && _physics->getFITKAcousticsSpectraManager() == nullptr)return box;
        for (Acoustics::FITKAcousticsAbstractSpectra* specData :
            _physics->getFITKAcousticsSpectraManager()->getSpectraByType(Acoustics::FITKAcousticsAbstractSpectra::AcousticsSpectraType::Damping))
        {
            if (specData == nullptr)continue;
            box->addItem(specData->getDataObjectName(), specData->getDataObjectID());
        }

        return box;
    }
}